/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Processor.ProcessControl;

import Data.ActivityLog.ActivityCrl;
import CrlException.CrlException;
import Data.Frontier.URLCrl;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import Config.ConfigSetting;

/**
 *
 * @author CUHUUHOANG
 */
public class ProcessThreadControl extends Thread {

    private static List<ProcessThread> AllProcessThreads;
    private static boolean isUsingProThreadLst;
    ExecutorService executorService;
    int corePoolSize;
    int maximumPoolSize;
    int keepAliveTime;
    boolean isSuspended;
    boolean isStopped;

    public ProcessThreadControl(int corePoolSize, int maximumPoolSize, int keepAliveTime) throws CrlException {
        try {
            AllProcessThreads = new ArrayList<ProcessThread>();
            executorService = new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
                    keepAliveTime, TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<Runnable>());
            this.corePoolSize = corePoolSize;
            this.maximumPoolSize = maximumPoolSize;
            this.keepAliveTime = keepAliveTime;

            isSuspended = false;
            isStopped = false;
            isUsingProThreadLst = false;
        } catch (Exception e) {
            throw new CrlException(e.getMessage());
        }

    }

    public ProcessThreadControl() throws CrlException {
        try {
            AllProcessThreads = new ArrayList<ProcessThread>();

            this.corePoolSize = 4;
            this.maximumPoolSize = 8;
            this.keepAliveTime = 5000;

            executorService = new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
                    keepAliveTime, TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<Runnable>());
            isSuspended = false;
            isStopped = false;
            isUsingProThreadLst = false;
        } catch (Exception e) {
            throw new CrlException(e.getMessage());
        }

    }

    public void CreateProcesses() throws CrlException {
        try {
            int time = 200;
            while (!isStopped) {
                while (getSize() < ConfigSetting.maxThread && URLCrl.urlDT.getSize() > 0 && !isSuspended && !isStopped) {
                    ProcessThread pt = new ProcessThread();
                    addThread(pt);
                    executorService.execute(pt);
                    time = (int) (time * 0.9);
                }
                checkTheadSuspend();
                time = (int) (time * 1.1);
                Thread.currentThread().sleep(time);
            }
        } catch (Exception e) {
            throw new CrlException(e.getMessage());
        }

    }

    @Override
    public void run() {
        try {
            CreateProcesses();
        } catch (CrlException ex) {
            ActivityCrl.atiData.addAtivity(ex.getMessage());
        }
    }

    synchronized public void SuspendProcesses(boolean isSuspend) throws CrlException {
        try {
            this.isSuspended = isSuspend;
            for (Iterator<ProcessThread> it = AllProcessThreads.iterator(); it.hasNext();) {
                ProcessThread p = it.next();
                p.suspendThread(isSuspend);
            }
            notifyAll();

        } catch (Exception ex) {
            throw new CrlException(ex.getMessage());
        }
    }

    synchronized public void checkTheadSuspend() throws CrlException {
        try {
            if (isSuspended) wait();
        } catch (Exception ex) {
            throw new CrlException(ex.getMessage());
        }

    }

    synchronized public void StopThead() throws CrlException {
        try {
            this.isStopped = true;
            this.isSuspended = false;
            for (Iterator<ProcessThread> it = AllProcessThreads.iterator(); it.hasNext();) {
                ProcessThread p = it.next();
                p.StopThread();
            }
            AllProcessThreads = null;
            notifyAll();
        } catch (Exception ex) {
            throw new CrlException(ex.getMessage());
        }

    }

    synchronized public void addThread(ProcessThread proThread) throws CrlException {
        try {
            if (isUsingProThreadLst) wait();
            isUsingProThreadLst = true;
            //do job
            if (!AllProcessThreads.contains(proThread)) {
                AllProcessThreads.add(proThread);
            }
            //end job
            isUsingProThreadLst = false;
            notifyAll();
        } catch (Exception ex) {
            throw new CrlException(ex.getMessage());
        }

    }

    synchronized public void removeThread(ProcessThread proThread) throws CrlException {
        try {
            if (isUsingProThreadLst) wait();
            isUsingProThreadLst = true;
            //do job
            if (AllProcessThreads.contains(proThread)) {
                AllProcessThreads.remove(proThread);
            }
            //end job
            isUsingProThreadLst = false;
            notifyAll();
        } catch (Exception ex) {
            throw new CrlException(ex.getMessage());
        }

    }

    synchronized public int getSize() throws CrlException {
        try {
            if (isUsingProThreadLst) wait();
            isUsingProThreadLst = true;
            //do job
            int out = 0;
            if (AllProcessThreads != null) {
                out = AllProcessThreads.size();
            }
            //end job
            isUsingProThreadLst = false;
            notifyAll();
            return out;
        } catch (Exception ex) {
            throw new CrlException(ex.getMessage());
        }

    }
}
